package wscmd

import (
	"go.uber.org/zap"
	"sync"
	"wzgames/internal/admin/adcomm"
	"wzgames/internal/codec/sfs"
	"wzgames/internal/constant"
	"wzgames/internal/gvalidator"
	"wzgames/internal/response"
	"wzgames/pkg/logger"
)

var (
	cmdSv *CmdSV
	once  sync.Once
)

type CmdSV struct {
	mu  sync.RWMutex
	fns map[string]adcomm.WsCmdFn
}

func Cmd() *CmdSV {
	if cmdSv == nil {
		once.Do(func() {
			cmdSv = &CmdSV{
				fns: make(map[string]adcomm.WsCmdFn),
			}
		})
	}
	return cmdSv
}

func (c *CmdSV) checkMessage(msg *sfs.TSfsObject, adminId int64) (int16, string) {
	data := msg.GetContent()
	if data == nil {
		return response.ErrBadRequest, constant.EmptyStr
	}

	cmdKey := data.GetUtfString(sfs.CmdKey)
	if !c.validateCmd(cmdKey) {
		logger.Warn("[WsCmd] illegal cmd key", zap.Int64("AdminId", adminId), zap.String("CmdKey", cmdKey))
		return response.ErrBadRequest, constant.EmptyStr
	}

	return 0, cmdKey
}

func (c *CmdSV) validateCmd(s string) bool {
	l := len(s)
	if !gvalidator.IsAlphaNumeric1(s) || l < 1 || l > 255 {
		return false
	}
	return true
}

func (c *CmdSV) RegisterCmd(cmd string, fn adcomm.WsCmdFn) {
	c.mu.Lock()
	c.fns[cmd] = fn
	c.mu.Unlock()
}

func (c *CmdSV) DoMessage(admin adcomm.IAdmin, data interface{}) {
	switch m := data.(type) {
	case *sfs.TSfsObject:
		code, cmd := c.checkMessage(m, admin.AdminId())
		if code != 0 {
			return
		}
		c.mu.RLock()
		fn, ok := c.fns[cmd]
		c.mu.RUnlock()
		if ok {
			fn(admin, m)
		} else {
			logger.Warn("[WsCmd] invalid cmd key", zap.Int64("AdminId", admin.AdminId()), zap.String("CmdKey", cmd))
		}
	default:
		logger.Warn("[WsCmd] unknown message on DoMessage", zap.Int64("AdminId", admin.AdminId()))
	}
}

func InitCmd() {
	Cmd()
	cmdSv.RegisterCmd(adcomm.KeyBetPendingUssCount, getBetPendingUnCheckCount)
	cmdSv.RegisterCmd(adcomm.KeyBetPendingUssSettle1, betPendingSettle1)
	cmdSv.RegisterCmd(adcomm.KeyBetPendingUssSettle2, betPendingSettle2)
	cmdSv.RegisterCmd(adcomm.KeyBetPendingUssSettle3, betPendingSettle3)
	cmdSv.RegisterCmd(adcomm.KeyBetPendingUssSettle4, betPendingSettle4)

	cmdSv.RegisterCmd(adcomm.KeyRouBigDrawLottery, rouDrawLottery)
	cmdSv.RegisterCmd(adcomm.KeyRouBetPendingUssSettle, rouBetPendingSettle)

	registerAdminCmds()
	registerSysCmds()
}
